#include "ws.unpacker.h"

#ifdef DEBUG
#include <iostream>
#endif

TOB::WS::Unpacker::Unpacker(TOB::WS::Packer& packer) {
  int bufferSize = PACKSIZE * packer.getCount();
  char* buffer = new char[bufferSize];
  int offset = 0;
  
  for (int i = 0; i < packer.getCount(); ++i) {
    memcpy(buffer + offset, packer[i].data, packer[i].length);
    offset += packer[i].length;
  }
  
  // pop func, first 4 bytes
  offset = 0;
  _func = *((TOB::WS::Function::Type*)(buffer + offset));
  offset += sizeof(TOB::WS::Function::Type);
  
  // tmp data
  int tmpl = 0;
  char* tmpCharArray = NULL;
  
  // pop request
  tmpl = *((int*)(buffer + offset));
  offset += sizeof(int);
  if (tmpl < 0 || tmpl > (bufferSize - offset)) {
    delete[] buffer;
    throw TOB::WS::UnpackerException("Error: can't read request.");
    return;
  }
  tmpCharArray = new char[tmpl];
  memcpy(tmpCharArray, buffer + offset, tmpl);
  offset += tmpl;
  _request = tmpCharArray;
  _request.resize(tmpl);
  delete[] tmpCharArray;
  
  // pop username
  tmpl = *((int*)(buffer + offset));
  offset += sizeof(int);
  if (tmpl < 0 || tmpl > (bufferSize - offset)) {
    delete[] buffer;
    throw TOB::WS::UnpackerException("Error: can't read user name.");
    return;
  }
  tmpCharArray = new char[tmpl];
  memcpy(tmpCharArray, buffer + offset, tmpl);
  offset += tmpl;
  _username = tmpCharArray;
  _username.resize(tmpl);
  delete[] tmpCharArray;
  
  // pop password
  tmpl = *((int*)(buffer + offset));
  offset += sizeof(int);
  if (tmpl < 0 || tmpl > (bufferSize - offset)) {
    delete[] buffer;
    throw TOB::WS::UnpackerException("Error: can't read password.");
    return;
  }
  tmpCharArray = new char[tmpl];
  memcpy(tmpCharArray, buffer + offset, tmpl);
  offset += tmpl;
  _password = tmpCharArray;
  _password.resize(tmpl);
  delete[] tmpCharArray;
  
  // pop nsip
  tmpl = *((int*)(buffer + offset));
  offset += sizeof(int);
  if (tmpl < 0 || tmpl > (bufferSize - offset)) {
    delete[] buffer;
    throw TOB::WS::UnpackerException("Error: can't read nsip.");
    return;
  }
  tmpCharArray = new char[tmpl];
  memcpy(tmpCharArray, buffer + offset, tmpl);
  offset += tmpl;
  _nsip = *((TOB::Nameserver::IP*)tmpCharArray);
  delete[] tmpCharArray;
  
  // pop data
  tmpl = *((int*)(buffer + offset));
  offset += sizeof(int);
  if (tmpl < 0 || tmpl > (bufferSize - offset)) {
    delete[] buffer;
    throw TOB::WS::UnpackerException("Error: can't read data.");
    return;
  }
  tmpCharArray = new char[tmpl];
  memcpy(tmpCharArray, buffer + offset, tmpl);
  offset += tmpl;
  TOB::WS::Data* tmpData = new TOB::WS::Data(tmpCharArray, tmpl);
  _data = *tmpData;
  delete[] tmpCharArray;
  delete tmpData;
  
  delete[] buffer;
  
#ifdef DEBUG
  std::cout << "created unpacker: " << this << std::endl;
#endif
}

TOB::WS::Unpacker::Unpacker() {
#ifdef DEBUG
  std::cout << "created unpacker: " << this << std::endl;
#endif
}

TOB::WS::Unpacker::~Unpacker() {
#ifdef DEBUG
  std::cout << "deleted unpacker: " << this << std::endl;
#endif
}

TOB::WS::Data& TOB::WS::Unpacker::getData() {
  return _data;
}

TOB::Nameserver::IP TOB::WS::Unpacker::getNSIP() {
  return _nsip;
}

std::string TOB::WS::Unpacker::getRequest() {
  return _request;
}

std::string TOB::WS::Unpacker::getUsername() {
  return _username;
}

std::string TOB::WS::Unpacker::getPassword() {
  return _password;
}

TOB::WS::Function::Type& TOB::WS::Unpacker::getFunc() {
  return _func;
}

TOB::WS::UnpackerException::UnpackerException(std::string error) {
  TOB::Log::error("WebServer::Unpacker: " + error);
}
